package com.tj.collection.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fqgj.base.services.amazon.AmazonS3Service;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.api.Page;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.common.utils.MD5;
import com.fqgj.common.utils.StringUtils;
import com.fqgj.exception.common.ApplicationException;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.jsoniter.output.JsonStream;
import com.tj.collection.bean.RedisKey;
import com.tj.collection.db.dao.*;
import com.tj.collection.db.domain.Admin;
import com.tj.collection.db.entity.*;
import com.tj.collection.db.entity.business.ClAllocationInfoEntity;
import com.tj.collection.db.entity.business.ClOrderAllocationEntity;
import com.tj.collection.db.entity.business.UniqueStatsVo;
import com.tj.collection.db.service.AdminService;
import com.tj.collection.enums.*;
import com.tj.collection.service.dto.CollectionDataDto;
import com.tj.collection.service.param.ClOrderSearchConditions;
import com.tj.collection.service.param.ClSearchConditions;
import com.tj.collection.service.request.*;
import com.tj.collection.task.AllocationJob;
import com.tj.collection.utils.CalculatorUtils;
import com.tj.collection.utils.ConfigUtil;
import com.tj.collection.utils.SerialNumberUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 * User: sm
 * Date: 2019-09-03
 * Time: 09:38
 * <p>
 * 催收模块新的逻辑
 * <p>
 * 各自需要再做拆分
 */
@Service
public class AllocationService {

    private static final Log LOGGER = LogFactory.getLog(AllocationService.class);

    @Autowired
    private ClReceiverDao receiverDao;

    @Autowired
    private ClReceiverDetailDao receiverDetailDao;


    @Autowired
    private ClImagesDao imagesDao;

    @Autowired
    private ClMerchantDao clMerchantDao;

    @Autowired
    private ClRepayFlowDao repayFlowDao;

    @Autowired
    private ClAllocationDetailDao allocationDetailDao;

    @Autowired
    private AllocationJob allocationJob;

    @Autowired
    private ClAgentsDao agentsDao;

    @Autowired
    private ClAllocationBatchDao allocationBatchDao;

    @Autowired
    private ClCommentDao clCommentDao;

    @Autowired
    private AdminService adminService;

    @Autowired
    private ConfigUtil configUtil;

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private AmazonS3Service amazonS3Service;

    /**
     * 需要重新分单的adminId， 新支持的语言
     *
     * @param adminId
     * @param languages
     */
    public void deleteAgent(Integer adminId, List<String> languages) {
        LOGGER.info("== deleteAgent 开始撤回所有分单 ==");
        List<ClAllocationBatchEntity> activeListByAdminId = allocationBatchDao.getActiveListByAdminId(adminId);
        if (CollectionUtils.isEmpty(activeListByAdminId)) {
            LOGGER.info("== deleteAgent 开始撤回所有分单  没有批次==");
            return;
        }

        LOGGER.info("== deleteAgent 开始撤回所有分单  有批次==");
        activeListByAdminId.forEach(allocationBatchEntity -> {
            String batchNo = allocationBatchEntity.getBatchNo();
            List<ClAllocationDetailEntity> listByBatchNo = allocationDetailDao.getListByBatchNo(batchNo);

            List<String> collectionNos = new ArrayList<>();
            List<String> allocationNos = new ArrayList<>();
            Map<String, String> allocationAndMap = new HashMap<>();

            listByBatchNo.forEach(dt -> {
                if (dt.getStatus().equals(AllocationStatusEnum.COLLECTING.getStatus()) || dt.getStatus().equals(AllocationStatusEnum.INIT.getStatus())) {
                    collectionNos.add(dt.getCollectionNo());
                    allocationNos.add(dt.getAllocationNo());
                    allocationAndMap.put(dt.getCollectionNo(), dt.getAllocationNo());
                }
            });


            if (!CollectionUtils.isEmpty(collectionNos)) {

                if (CollectionUtils.isEmpty(collectionNos)) {
                    return;
                }

                List<ClReceiverEntity> receiverEntityList = receiverDao.selectByCollectionNos(collectionNos);
                Map<String, String> collectionNoAndLanguageMap = new HashMap<>();
                receiverEntityList.forEach(r -> {
                    collectionNoAndLanguageMap.put(r.getCollectionNo(), r.getUserLanguage());
                });


                List<String> collectionNosNew = new ArrayList<>();
                List<String> allocationNosNew = new ArrayList<>();
                collectionNos.forEach(c -> {
                    if (CollectionUtils.isNotEmpty(languages)) {
                        if (!languages.contains(collectionNoAndLanguageMap.get(c))) {
                            collectionNosNew.add(c);
                            allocationNosNew.add(allocationAndMap.get(c));
                        }
                    } else {
                        collectionNosNew.addAll(collectionNos);
                        allocationNosNew.addAll(allocationNos);
                    }
                });

                if (CollectionUtils.isEmpty(collectionNosNew)) {
                    return;
                }

                //detail置为无效
                List<Integer> sourceStatus = new ArrayList<>();
                sourceStatus.add(AllocationStatusEnum.COLLECTING.getStatus());
                sourceStatus.add(AllocationStatusEnum.INIT.getStatus());
                allocationDetailDao.updateStatusByAllocationNosAndStatus(allocationNosNew, sourceStatus, AllocationStatusEnum.INVALID.getStatus());

                //receiver置为待分配
                receiverDao.updateStatusByCollectionNos(collectionNosNew, ReceiverStatusEnum.INIT.getStatus());
            }
        });
    }

    /**
     * 收单
     *
     * @param request
     */
    @Transactional(rollbackFor = Exception.class)
    public void receiver(ClOrderReceiveRequest request) {
        LOGGER.info("催收收单,request:{}", JSON.toJSONString(request));
        ClMerchantEntity clMerchantEntity = clMerchantDao.selectClMerchantEntityByToken(request.getToken());
        if (clMerchantEntity == null) {
            throw new ApplicationException("Verification failed");
        }
        //数据校验
        String result = dataCheck(request, clMerchantEntity);
        if (StringUtils.isNotEmpty(result)) {
            LOGGER.info("催收收单数据校验失败,request:{}", JSON.toJSONString(request));
            throw new ApplicationException(result);
        }

        //含默认值的字段补全
        dataCompletion(request, clMerchantEntity);

        Date repaymentDate = DateUtil.getDate(request.getOrderInfo().getRepaymentDate(), "yyyy-MM-dd");

        List<ClReceiverEntity> clReceiverEntityList = receiverDao.selectListByBillNo(request.getOrderBillNo());
        if (CollectionUtils.isNotEmpty(clReceiverEntityList)) {
            for (ClReceiverEntity re : clReceiverEntityList) {
                ClReceiverDetailEntity clReceiverDetailEntity = receiverDetailDao.selectOneByCollectionNo(re.getCollectionNo());
                //兼容展期订单，如果存在还款日相同的订单，则表示无需重复处理，若还款日不同，作为展期订单处理，生成新的催收单号
                if (DateUtil.diffDate(clReceiverDetailEntity.getRepaymentDate(), repaymentDate) == 0) {
                    LOGGER.error("账单已经存在,billNo:{}", request.getOrderBillNo());
                    return;
                }
            }
            if (request.getOrderInfo().getExtensionNumber() == null) {
                throw new ApplicationException("展期序号不能为空");
            }
        }

        //收单
        String collectionNo = SerialNumberUtil.getBizOrderNumber(AdminNumberRuleEnum.COLLECTION);
        Integer overdueDays = DateUtil.diffDate(new Date(), repaymentDate);
        ClReceiverEntity receiverEntity = new ClReceiverEntity()
                .setOrderNo(request.getTradeNo())
                .setBillNo(request.getOrderBillNo())
                .setBorrowType(request.getOrderInfo().getBorrowType())
                .setCollectionNo(collectionNo)

                .setCreateDt(new Date())
                .setMerchantCode(clMerchantEntity.getMerchantCode())
                .setOverdueDays(overdueDays)
                .setUserCode(request.getUserCode())

                .setStatus(ReceiverStatusEnum.INIT.getStatus())
                .setUserLanguage(request.getUserInfo().getUserLanguage())
                .setSourceMerchantCode(clMerchantEntity.getMerchantCode())
                .setExtensionNumber(request.getOrderInfo().getExtensionNumber() == null ? 0 : request.getOrderInfo().getExtensionNumber())
                .setExtensionStatus(ExtensionStatusEnum.UN_EXTENSION.getStatus())
                .setOriginNo(request.getOriginOrderNo());

        receiverDao.insert(receiverEntity);

        //保存详细信息
        ClReceiverDetailEntity clReceiverDetailEntity = new ClReceiverDetailEntity();
        clReceiverDetailEntity.setCollectionNo(collectionNo);
        clReceiverDetailEntity.setName(request.getUserInfo().getName());
        clReceiverDetailEntity.setMobile(request.getUserInfo().getMobile());
        clReceiverDetailEntity.setIdentityNo(request.getUserInfo().getKycNo());
        clReceiverDetailEntity.setChannel(request.getOrderInfo().getChannel());
        clReceiverDetailEntity.setOrderSource(ChannelMappingEnum.getSourceByChannel(request.getOrderInfo().getChannel()));
        clReceiverDetailEntity.setPeriod(1);
        clReceiverDetailEntity.setTotalPeriod(1);
        clReceiverDetailEntity.setCapitalCode(request.getOrderInfo().getCapitalCode());
        clReceiverDetailEntity.setProductCode(request.getProductCode());
        clReceiverDetailEntity.setProductType(request.getProductType());
        clReceiverDetailEntity.setAppName(request.getAppName());
        clReceiverDetailEntity.setBorrowCapital(new BigDecimal(request.getOrderInfo().getBorrowCapital()));
        clReceiverDetailEntity.setReceivedCapital(new BigDecimal(request.getOrderInfo().getReceivedCapital()));
        clReceiverDetailEntity.setReceivedDate(DateUtil.getDate(request.getOrderInfo().getReceivedDate(), "yyyy-MM-dd"));
        clReceiverDetailEntity.setPaidAmount(new BigDecimal(request.getOrderInfo().getPaidAmount()));
        clReceiverDetailEntity.setDeductAmount(new BigDecimal(request.getOrderInfo().getDeductAmount()));
        clReceiverDetailEntity.setInterest(new BigDecimal(request.getOrderInfo().getInterest()));
        clReceiverDetailEntity.setServiceFee(new BigDecimal(request.getOrderInfo().getServiceFee()));
        clReceiverDetailEntity.setLateServiceFee(new BigDecimal(request.getOrderInfo().getLateServiceFee()));
        clReceiverDetailEntity.setLateFeeRatio(new BigDecimal(request.getOrderInfo().getLateFeeRatio()));
        clReceiverDetailEntity.setRepaymentDate(DateUtil.getDate(request.getOrderInfo().getRepaymentDate(), "yyyy-MM-dd"));
        clReceiverDetailEntity.setActualRepaymentDate(null);
        clReceiverDetailEntity.setProvince(request.getUserInfo().getState());
        clReceiverDetailEntity.setCity(request.getUserInfo().getCity());
        clReceiverDetailEntity.setAddress(request.getUserInfo().getAddress());
        clReceiverDetailEntity.setEmail(request.getUserInfo().getEmail());
        clReceiverDetailEntity.setSex(request.getUserInfo().getSex());
        clReceiverDetailEntity.setBirthday(DateUtil.getDate(DateUtil.getDate(request.getUserInfo().getBirthday(), "yyyy-MM-dd")));
        clReceiverDetailEntity.setPanCardNo(request.getUserInfo().getPanCardNo());
        clReceiverDetailEntity.setAadhaarNo(request.getUserInfo().getAadhaarNo());
        clReceiverDetailEntity.setEducation(request.getUserInfo().getEducation());
        clReceiverDetailEntity.setMarriedStatus(request.getUserInfo().getMarriedStatus());
        clReceiverDetailEntity.setContact1Name(request.getUserInfo().getContact1Name());
        clReceiverDetailEntity.setContact1Mobile(request.getUserInfo().getContact1Mobile());
        clReceiverDetailEntity.setContact1Relative(request.getUserInfo().getContact1Relative());
        clReceiverDetailEntity.setContact2Name(request.getUserInfo().getContact2Name());
        clReceiverDetailEntity.setContact2Mobile(request.getUserInfo().getContact2Mobile());
        clReceiverDetailEntity.setContact2Relative(request.getUserInfo().getContact2Relative());
        clReceiverDetailEntity.setPinCode(request.getUserInfo().getPinCode());
        clReceiverDetailEntity.setExtData("");
        clReceiverDetailEntity.setContactUrl(request.getUserInfo().getContactUrl())
                .setTotalMoney(new BigDecimal(request.getOrderInfo().getTotalMoney()))
                .setRemainMoney(new BigDecimal(request.getOrderInfo().getRemainMoney()))
        ;
        receiverDetailDao.insert(clReceiverDetailEntity);

        List<String> images = request.getUserInfo().getImages();
        if(CollectionUtils.isNotEmpty(images)){
            ClImagesEntity clImagesEntity = new ClImagesEntity()
                    .setCollectionNo(collectionNo)
                    .setImagesJson(JsonStream.serialize(images));
            imagesDao.insert(clImagesEntity);
        }


        LOGGER.info("催收收单成功,tradeNo:{}", request.getTradeNo());
    }

    /**
     * 收单
     *
     * @param request
     */
    @Transactional(rollbackFor = Exception.class)
    public void receiverUpdate(ClOrderReceiveRequest request) {
        LOGGER.info("催收信息更新,request:{}", JSON.toJSONString(request));
        ClMerchantEntity clMerchantEntity = clMerchantDao.selectClMerchantEntityByToken(request.getToken());
        if (clMerchantEntity == null) {
            throw new ApplicationException("Verification failed");
        }
        //数据校验
        String result = dataCheck(request, clMerchantEntity);
        if (StringUtils.isNotEmpty(result)) {
            LOGGER.info("催收收单数据校验失败,request:{}", JSON.toJSONString(request));
            throw new ApplicationException(result);
        }

        //含默认值的字段补全
        dataCompletion(request, clMerchantEntity);

        Date repaymentDate = DateUtil.getDate(request.getOrderInfo().getRepaymentDate(), "yyyy-MM-dd");

        ClReceiverEntity clReceiverEntityHis = null;
        ClReceiverDetailEntity clReceiverDetailEntityHis = null;
        List<ClReceiverEntity> clReceiverEntityList = receiverDao.selectListByBillNo(request.getOrderBillNo());
        if (CollectionUtils.isNotEmpty(clReceiverEntityList)) {
            for (ClReceiverEntity re : clReceiverEntityList) {
                ClReceiverDetailEntity clReceiverDetailEntity = receiverDetailDao.selectOneByCollectionNo(re.getCollectionNo());
                //兼容展期订单，如果存在还款日相同的订单，则表示无需重复处理，若还款日不同，作为展期订单处理，生成新的催收单号
                if (DateUtil.diffDate(clReceiverDetailEntity.getRepaymentDate(), repaymentDate) == 0) {
                    LOGGER.info("找到对应账单,tradeNo:{},billNo:{}", request.getTradeNo(), request.getOrderBillNo());
                    clReceiverEntityHis = re;
                    clReceiverDetailEntityHis = clReceiverDetailEntity;
                }
            }
            if (request.getOrderInfo().getExtensionNumber() == null) {
                throw new ApplicationException("展期序号不能为空");
            }
        }
        if (clReceiverEntityHis == null || clReceiverDetailEntityHis == null) {
            LOGGER.info("催收订单不存在无法更新,tradeNo:{},billNo:{}", request.getTradeNo(), request.getOrderBillNo());
            return;
        }

        String collectionNo = clReceiverEntityHis.getCollectionNo();

        //保存详细信息
        ClReceiverDetailEntity clReceiverDetailEntity = new ClReceiverDetailEntity();
        clReceiverDetailEntity.setId(clReceiverDetailEntityHis.getId());
        clReceiverDetailEntity.setCollectionNo(collectionNo);
        clReceiverDetailEntity.setName(request.getUserInfo().getName());
        clReceiverDetailEntity.setMobile(request.getUserInfo().getMobile());
        clReceiverDetailEntity.setIdentityNo(request.getUserInfo().getKycNo());
        clReceiverDetailEntity.setChannel(request.getOrderInfo().getChannel());
        clReceiverDetailEntity.setOrderSource(ChannelMappingEnum.getSourceByChannel(request.getOrderInfo().getChannel()));
        clReceiverDetailEntity.setPeriod(1);
        clReceiverDetailEntity.setTotalPeriod(1);
        clReceiverDetailEntity.setCapitalCode(request.getOrderInfo().getCapitalCode());
        clReceiverDetailEntity.setProductCode(request.getProductCode());
        clReceiverDetailEntity.setProductType(request.getProductType());
        clReceiverDetailEntity.setAppName(request.getAppName());
        clReceiverDetailEntity.setBorrowCapital(new BigDecimal(request.getOrderInfo().getBorrowCapital()));
        clReceiverDetailEntity.setReceivedCapital(new BigDecimal(request.getOrderInfo().getReceivedCapital()));
        clReceiverDetailEntity.setReceivedDate(DateUtil.getDate(request.getOrderInfo().getReceivedDate(), "yyyy-MM-dd HH:mm:ss"));
        clReceiverDetailEntity.setPaidAmount(new BigDecimal(request.getOrderInfo().getPaidAmount()));
        clReceiverDetailEntity.setDeductAmount(new BigDecimal(request.getOrderInfo().getDeductAmount()));
        clReceiverDetailEntity.setInterest(new BigDecimal(request.getOrderInfo().getInterest()));
        clReceiverDetailEntity.setServiceFee(new BigDecimal(request.getOrderInfo().getServiceFee()));
        clReceiverDetailEntity.setLateServiceFee(new BigDecimal(request.getOrderInfo().getLateServiceFee()));
        clReceiverDetailEntity.setLateFeeRatio(new BigDecimal(request.getOrderInfo().getLateFeeRatio()));
        clReceiverDetailEntity.setRepaymentDate(DateUtil.getDate(request.getOrderInfo().getRepaymentDate(), "yyyy-MM-dd"));
        clReceiverDetailEntity.setActualRepaymentDate(null);
        clReceiverDetailEntity.setProvince(request.getUserInfo().getState());
        clReceiverDetailEntity.setCity(request.getUserInfo().getCity());
        clReceiverDetailEntity.setAddress(request.getUserInfo().getAddress());
        clReceiverDetailEntity.setEmail(request.getUserInfo().getEmail());
        clReceiverDetailEntity.setSex(request.getUserInfo().getSex());
        clReceiverDetailEntity.setBirthday(DateUtil.getDate(DateUtil.getDate(request.getUserInfo().getBirthday(), "yyyy-MM-dd")));
        clReceiverDetailEntity.setPanCardNo(request.getUserInfo().getPanCardNo());
        clReceiverDetailEntity.setAadhaarNo(request.getUserInfo().getAadhaarNo());
        clReceiverDetailEntity.setEducation(request.getUserInfo().getEducation());
        clReceiverDetailEntity.setMarriedStatus(request.getUserInfo().getMarriedStatus());
        clReceiverDetailEntity.setContact1Name(request.getUserInfo().getContact1Name());
        clReceiverDetailEntity.setContact1Mobile(request.getUserInfo().getContact1Mobile());
        clReceiverDetailEntity.setContact1Relative(request.getUserInfo().getContact1Relative());
        clReceiverDetailEntity.setContact2Name(request.getUserInfo().getContact2Name());
        clReceiverDetailEntity.setContact2Mobile(request.getUserInfo().getContact2Mobile());
        clReceiverDetailEntity.setContact2Relative(request.getUserInfo().getContact2Relative());
        clReceiverDetailEntity.setPinCode(request.getUserInfo().getPinCode());
        clReceiverDetailEntity.setExtData("");
        receiverDetailDao.updateByPrimaryKey(clReceiverDetailEntity);

        LOGGER.info("催收信息更新成功,tradeNo:{}", request.getTradeNo());
    }

    /**
     * 更新通讯录
     *
     * @param request
     */
    public void saveUserContacts(ClOrderContactsRequest request) {
        LOGGER.info("更新通讯录,request:{}", JSON.toJSONString(request));
        ClMerchantEntity clMerchantEntity = clMerchantDao.selectClMerchantEntityByToken(request.getToken());
        if (clMerchantEntity == null) {
            throw new ApplicationException("Verification failed");
        }
        if (StringUtils.isEmpty(request.getTradeNo())) {
            throw new ApplicationException("tradeNo cannot be empty");
        }
        if (CollectionUtils.isEmpty(request.getContacts())) {
            throw new ApplicationException("Contacts cannot be empty");
        }
        ClReceiverEntity clReceiverEntity = receiverDao.selectLastByOrderNo(request.getTradeNo());
        if (clReceiverEntity == null) {
            throw new ApplicationException("Order does not exist");
        }

        JSONArray contacts = new JSONArray();
        for (ClContactsInputVo vo : request.getContacts()) {
            JSONObject j1 = new JSONObject();
            j1.put("name", vo.getName());
            j1.put("phone", vo.getMobile());
            contacts.add(j1);
        }
        JSONObject jsonData = new JSONObject();
        jsonData.put("contacts", contacts);

        if (CollectionUtils.isNotEmpty(request.getSmsList())) {
            jsonData.put("smsList", request.getSmsList());
        }

        String filePath = "collection/contact/";
        if (configUtil.isServerTest()) {
            filePath = "collection/test/contact/";
        }
        filePath += clReceiverEntity.getUserCode() + "_" + System.currentTimeMillis() + ".json";
        String url = configUtil.getAmazonS3BaseUrl() + amazonS3Service.uploadFile(filePath, jsonData.toJSONString());

        //通讯录更新入库
        ClReceiverDetailEntity clReceiverDetailEntity = receiverDetailDao.selectOneByCollectionNo(clReceiverEntity.getCollectionNo());
        String tmp = clReceiverDetailEntity.getContactUrl();

        clReceiverDetailEntity.setContactUrl(url);
        if (CollectionUtils.isNotEmpty(request.getSmsList())) {
            clReceiverDetailEntity.setSmsUrl(url);
        }
        receiverDetailDao.updateByPrimaryKey(clReceiverDetailEntity);
        LOGGER.info("通讯录更新入库成功,tradeNo:{},tmp:{},url{}", request.getTradeNo(), tmp, url);
    }

    public void remove(ClRepaymentRequest request) {
        LOGGER.info("removeUpdate,request:{}", JSON.toJSONString(request));
        ClMerchantEntity clMerchantEntity = clMerchantDao.selectClMerchantEntityByToken(request.getToken());
        if (clMerchantEntity == null) {
            throw new ApplicationException("Verification failed");
        }

        ClReceiverEntity receiverEntity = receiverDao.selectLastByBillNo(request.getOrderBillNo());
        if (receiverEntity == null) {
            LOGGER.info("removeUpdate催收中未能找到该笔支付对应的催收账单,billNo:{}", request.getOrderBillNo());
            return;
        }

        receiverEntity.setDeleted(true);
        receiverEntity.setStatus(ReceiverStatusEnum.PAUSED.getStatus());
        receiverDao.updateByPrimaryKey(receiverEntity);


        ClAllocationDetailEntity currentAllocation = allocationDetailDao.getCurrentAllocationByCollectionNo(receiverEntity.getCollectionNo());
        if (currentAllocation != null) {
            currentAllocation.setDeleted(true);
            currentAllocation.setStatus(AllocationStatusEnum.INVALID.getStatus());
            allocationDetailDao.updateByPrimaryKey(currentAllocation);
        }


    }
    public void recover(ClRepaymentRequest request) {
        LOGGER.info("removeUpdate,request:{}", JSON.toJSONString(request));
        ClMerchantEntity clMerchantEntity = clMerchantDao.selectClMerchantEntityByToken(request.getToken());
        if (clMerchantEntity == null) {
            throw new ApplicationException("Verification failed");
        }

        ClReceiverEntity receiverEntity = receiverDao.selectLastByBillNo(request.getOrderBillNo());
        if (receiverEntity == null) {
            LOGGER.info("removeUpdate催收中未能找到该笔支付对应的催收账单,billNo:{}", request.getOrderBillNo());
            return;
        }

        receiverEntity.setDeleted(false);
        receiverEntity.setStatus(ReceiverStatusEnum.ALLOCATE_SUCCESS.getStatus());
        receiverDao.updateByPrimaryKey(receiverEntity);


        ClAllocationDetailEntity currentAllocation = allocationDetailDao.getCurrentAllocationByCollectionNo(receiverEntity.getCollectionNo());
        if (currentAllocation != null) {
            currentAllocation.setDeleted(false);
            currentAllocation.setStatus(AllocationStatusEnum.COLLECTING.getStatus());
            allocationDetailDao.updateByPrimaryKey(currentAllocation);
        }

    }

    /**
     * 还款通知
     *
     * @param request
     */
    @Transactional(rollbackFor = Exception.class)
    public void repaymentUpdate(ClRepaymentRequest request) {
        LOGGER.info("催收还款通知,request:{}", JSON.toJSONString(request));
        ClMerchantEntity clMerchantEntity = clMerchantDao.selectClMerchantEntityByToken(request.getToken());
        if (clMerchantEntity == null) {
            throw new ApplicationException("Verification failed");
        }
        //数据校验
        String result = dataCheck(request);
        if (StringUtils.isNotEmpty(result)) {
            LOGGER.info("催收还款通知数据校验失败,request:{}", JSON.toJSONString(request));
            throw new ApplicationException(result);
        }

        //找到当前订单在谁的手上
        String billNo = request.getOrderBillNo();
        ClReceiverEntity receiverEntity = receiverDao.selectLastByBillNo(billNo);
        if (receiverEntity == null) {
            LOGGER.info("催收中未能找到该笔支付对应的催收账单,billNo:{}", billNo);
            return;
        }
        //判断当前的分单是否正常
        String collectionNo = receiverEntity.getCollectionNo();
        boolean isClear = request.getPaidStatus() == 2;
        Date repaymentDate = DateUtil.getDate(request.getRepayDate(), "yyyy-MM-dd HH:mm:ss");

        ClReceiverDetailEntity receiverDetailEntity = receiverDetailDao.selectOneByCollectionNo(collectionNo);
        if (ReceiverStatusEnum.COLLECTION_END.getStatus().equals(receiverEntity.getStatus())
                && receiverDetailEntity.getActualRepaymentDate() != null) {
            LOGGER.error("催收单已经处于终止状态不再处理,billNo:{},collectionNo:{}", billNo, receiverEntity.getCollectionNo());
            return;
        } else if (ReceiverStatusEnum.COLLECTION_END.getStatus().equals(receiverEntity.getStatus())) {
            LOGGER.warn("催收单已经处于终止作数据订正,billNo:{},collectionNo:{}", billNo, receiverEntity.getCollectionNo());
            return;
        }

        //查询流水是否重复
        ClRepayFlowEntity clRepayFlowEntity = repayFlowDao.selectByRepaymentFlowNo(request.getRepayBizNo());
        if (clRepayFlowEntity != null) {
            LOGGER.error("当前支付流水号已经存在,billNo:{}", billNo);
            return;
        }

        //根据还款时间筛选催收单
        ClAllocationDetailEntity allocationDetailEntity = allocationDetailDao.getLatestRecordByCollectionNoAndRepaymentDate(collectionNo, repaymentDate);
        //催收单结清处理
        if (allocationDetailEntity != null) {
            //更新当前催收单的状态
            allocationDetailEntity.setStatus(AllocationStatusEnum.COLLECTION_END.getStatus());
            allocationDetailDao.updateByPrimaryKey(allocationDetailEntity);
            LOGGER.info("催收单结清成功,allocationNo:{},collectionNo:{}", allocationDetailEntity.getAllocationNo(), collectionNo);
            //如果当前销账的分单记录后续被分配过 那么需要把这笔之后的分单都置为失效
            int num = allocationDetailDao.updateAllocationInvalid(collectionNo, allocationDetailEntity.getId());
            if (num > 0) {
                LOGGER.info("后续催收单置为失效,collectionNo:{},num:{}", collectionNo, num);
            }
        } else {
            //根据还款时间找不到催收单，那就找最新的有效催收单，将其设置为结清
            ClAllocationDetailEntity currentAllocationByCollectionNo = allocationDetailDao.getLatestByCollectionNoAndLessThanDate(collectionNo, repaymentDate);
            if (currentAllocationByCollectionNo != null) {
                LOGGER.info("找到最新一笔有效的催收单结清,allocationNo:{},collectionNo:{}", currentAllocationByCollectionNo.getAllocationNo(), collectionNo);
                currentAllocationByCollectionNo.setStatus(AllocationStatusEnum.COLLECTION_END.getStatus());
                allocationDetailDao.updateByPrimaryKey(currentAllocationByCollectionNo);
            }
        }

        //插入还款流水
        ClRepayFlowEntity clRepayFlowEntity1 = new ClRepayFlowEntity()
                .setRepayBizNo(request.getRepayBizNo())
                .setAllocationNo(allocationDetailEntity == null ? "" : allocationDetailEntity.getAllocationNo())
                .setCollectionNo(collectionNo)
                .setDeductAmount(new BigDecimal(request.getDeductAmount()))
                .setPaidAmount(new BigDecimal(request.getPaidAmount()))
                .setRepayDate(repaymentDate);
        repayFlowDao.insert(clRepayFlowEntity1);

        //更新还款的总额数据
        receiverDetailEntity.setPaidAmount(new BigDecimal(request.getTotalPaidAmount()))
                .setDeductAmount(new BigDecimal(request.getTotalDeductAmount()))
                .setActualRepaymentDate(isClear ? repaymentDate : null);
        receiverDetailDao.updateByPrimaryKey(receiverDetailEntity);

        //催收收单表结清处理 还清了需要更细收单表状态、分半表状态。停止对当前订单的流转
        if (isClear) {
            receiverEntity.setStatus(ReceiverStatusEnum.COLLECTION_END.getStatus());
            receiverEntity.setCloseType(request.getPaidType());
            receiverDao.updateByPrimaryKey(receiverEntity);
        }
        LOGGER.info("催收还款处理成功,request:{}", JSON.toJSONString(request));
    }


    /**
     * 催收收到展期费通知
     * 执行催收单终止操作
     *
     * @param request
     */
    public void repaymentExtensionUpdate(ClRepaymentRequest request) {
        LOGGER.info("repaymentExtensionUpdate,催收收到展期费通知,request:{}", JSON.toJSONString(request));
        //找到当前订单在谁的手上
        String billNo = request.getOrderBillNo();
        ClReceiverEntity receiverEntity = receiverDao.selectLastByBillNo(billNo);
        if (receiverEntity == null) {
            LOGGER.info("repaymentExtensionUpdate,催收中未能找到该笔支付对应的催收账单,billNo:{}", billNo);
            return;
        }
        if (ReceiverStatusEnum.COLLECTION_END.getStatus().equals(receiverEntity.getStatus())) {
            LOGGER.error("repaymentExtensionUpdate,催收单已经处于终止状态不再处理,billNo:{},collectionNo:{}", billNo, receiverEntity.getCollectionNo());
            return;
        }

        //判断当前的分单是否是正常的
        String collectionNo = receiverEntity.getCollectionNo();
        Date repaymentDate = DateUtil.getDate(request.getRepayDate(), "yyyy-MM-dd HH:mm:ss");

        ClReceiverDetailEntity receiverDetailEntity = receiverDetailDao.selectOneByCollectionNo(collectionNo);

        //查询流水是否重复
        ClRepayFlowEntity clRepayFlowEntity = repayFlowDao.selectByRepaymentFlowNo(request.getRepayBizNo());
        if (clRepayFlowEntity != null) {
            LOGGER.error("repaymentExtensionUpdate,当前支付流水号已经存在,billNo:{}", billNo);
            return;
        }

        //根据还款时间筛选催收单
        ClAllocationDetailEntity allocationDetailEntity = allocationDetailDao.getLatestRecordByCollectionNoAndRepaymentDate(collectionNo, repaymentDate);
        //催收单结清处理
        if (allocationDetailEntity != null) {
            //更新当前催收单的状态
            allocationDetailEntity.setStatus(AllocationStatusEnum.COLLECTION_END.getStatus());
            allocationDetailDao.updateByPrimaryKey(allocationDetailEntity);
            LOGGER.info("repaymentExtensionUpdate,催收单结清成功,allocationNo:{},collectionNo:{}", allocationDetailEntity.getAllocationNo(), collectionNo);
            //如果当前销账的分单记录后续被分配过 那么需要把这笔之后的分单都置为失效
            int num = allocationDetailDao.updateAllocationInvalid(collectionNo, allocationDetailEntity.getId());
            if (num > 0) {
                LOGGER.info("repaymentExtensionUpdate,后续催收单置为失效,collectionNo:{},num:{}", collectionNo, num);
            }
        } else {
            //根据还款时间找不到催收单，那就找最新的有效催收单，将其设置为结清
            ClAllocationDetailEntity currentAllocationByCollectionNo = allocationDetailDao.getCurrentAllocationByCollectionNo(collectionNo);
            if (currentAllocationByCollectionNo != null) {
                LOGGER.info("repaymentExtensionUpdate,找到最新一笔有效的催收单结清,allocationNo:{},collectionNo:{}", currentAllocationByCollectionNo.getAllocationNo(), collectionNo);
                currentAllocationByCollectionNo.setStatus(AllocationStatusEnum.COLLECTION_END.getStatus());
                allocationDetailDao.updateByPrimaryKey(currentAllocationByCollectionNo);
            }
        }

        //插入还款流水
        ClRepayFlowEntity clRepayFlowEntity1 = new ClRepayFlowEntity()
                .setRepayBizNo(request.getRepayBizNo())
                .setAllocationNo(allocationDetailEntity == null ? "" : allocationDetailEntity.getAllocationNo())
                .setCollectionNo(collectionNo)
                .setDeductAmount(new BigDecimal(request.getDeductAmount()))
                .setPaidAmount(new BigDecimal(request.getPaidAmount()))
                .setRepayDate(repaymentDate);
        repayFlowDao.insert(clRepayFlowEntity1);

        //更新还款的总额数据
        receiverDetailEntity.setPaidAmount(new BigDecimal(request.getTotalPaidAmount()))
                .setDeductAmount(new BigDecimal(request.getTotalDeductAmount()))
                .setActualRepaymentDate(repaymentDate);
        receiverDetailDao.updateByPrimaryKey(receiverDetailEntity);

        //催收收单表结清处理 还清了需要更细收单表状态、分半表状态。停止对当前订单的流转
        receiverEntity.setStatus(ReceiverStatusEnum.COLLECTION_END.getStatus());
        receiverEntity.setCloseType(request.getPaidType());
        receiverDao.updateByPrimaryKey(receiverEntity);
        LOGGER.info("repaymentExtensionUpdate,催收展期费还款处理成功,request:{}", JSON.toJSONString(request));
    }

    /**
     * 根据真实还款日期清算应还金额
     *
     * @param clReceiverDetailEntity
     * @param repayDate
     * @return
     */
    private BigDecimal calculateExpiredAmount(ClReceiverDetailEntity clReceiverDetailEntity, Date repayDate) {
        BigDecimal expireAmount = new BigDecimal(0);
        BigDecimal lateFee = new BigDecimal(0);
        //lateFee和expiredAmount
        int overDueDays = DateUtil.diffDate(repayDate, clReceiverDetailEntity.getRepaymentDate());
        if (overDueDays > 0) {
            //算好lateFee后再加上lateServiceFee=总罚息
            lateFee = CalculatorUtils.calculateOverdueFee(clReceiverDetailEntity.getBorrowCapital(),
                    clReceiverDetailEntity.getLateFeeRatio(),
                    overDueDays).add(clReceiverDetailEntity.getLateServiceFee());
            expireAmount = clReceiverDetailEntity.getBorrowCapital().add(clReceiverDetailEntity.getInterest()).add(lateFee);
        } else {
            lateFee = new BigDecimal(0);
            expireAmount = clReceiverDetailEntity.getBorrowCapital().add(clReceiverDetailEntity.getInterest()).add(lateFee);
        }
        return expireAmount.setScale(2, BigDecimal.ROUND_HALF_UP);
    }


//    /**
//     * 撤单
//     */
//    public void cancelOrder(String billNo) {
//        //找到当前的batch_detail里面的订单  把入口订单置为待分配
//        ClReceiverEntity receiverEntity = receiverDao.selectByBillNo(billNo);
//        ClAllocationDetailEntity currentAllocationByCollectionNo = allocationDetailDao.getCurrentAllocationByCollectionNo(receiverEntity.getCollectionNo());
//        if (currentAllocationByCollectionNo == null) {
//            LOGGER.error("== 找不到当前订单的实际负责人，可能是当前订单不存在记录或者已经处理完成 ==");
//            return;
//        }
//
//        currentAllocationByCollectionNo.setStatus(AllocationStatusEnum.TRANSFERRED.getStatus());
//        allocationDetailDao.updateByPrimaryKey(currentAllocationByCollectionNo);
//
//        //更新入口表
//        if (!receiverEntity.getStatus().equals(ReceiverStatusEnum.COLLECTION_END.getStatus())) {
//            receiverEntity.setStatus(ReceiverStatusEnum.INIT.getStatus());
//            receiverDao.updateByPrimaryKey(receiverEntity);
//        }
//    }

    /**
     * 手动分单
     */
    public void manualAllocation(List<String> orderNos, Integer adminId, String createBy) {
        LOGGER.info("执行手动分单,orderNos:{},adminId:{}", JSON.toJSONString(orderNos), adminId);
        if (CollectionUtils.isEmpty(orderNos)) {
            LOGGER.error("== 手动分单找不到对应的账单 ==");
            return;
        }
        List<ClReceiverEntity> receiverEntityList = receiverDao.selectListByOrderNos(orderNos);
        if (CollectionUtils.isEmpty(receiverEntityList)) {
            LOGGER.error("== 手动分单找不到对应的账单 ==");
            return;
        }
        receiverEntityList.removeIf(entity -> (
                !ReceiverStatusEnum.INIT.getStatus().equals(entity.getStatus()) && !ReceiverStatusEnum.ALLOCATE_SUCCESS.getStatus().equals(entity.getStatus())
        ));

        ClAgentsEntity agentsEntity = agentsDao.getByAdminId(adminId);
        for (ClReceiverEntity clReceiverEntity : receiverEntityList) {
            if (!agentsEntity.getMerchantCode().equals(clReceiverEntity.getMerchantCode())) {
                throw new ApplicationException("Agent error!");
            }
        }

        receiverEntityList.forEach(r -> {
            r.setStatus(ReceiverStatusEnum.PAUSED.getStatus());
            receiverDao.updateByPrimaryKey(r);
        });

        List<String> collectNos = receiverEntityList.parallelStream().map(ClReceiverEntity::getCollectionNo).collect(Collectors.toList());
        collectNos.forEach(c -> {
            ClAllocationDetailEntity currentAllocationByCollectionNo = allocationDetailDao.getCurrentAllocationByCollectionNo(c);
            if (currentAllocationByCollectionNo != null) {
                LOGGER.info("手动分单触发流转操作,currentAllocation:{}", JSON.toJSONString(currentAllocationByCollectionNo));
                currentAllocationByCollectionNo.setStatus(AllocationStatusEnum.TRANSFERRED.getStatus());
                allocationDetailDao.updateByPrimaryKey(currentAllocationByCollectionNo);
            }
        });
        allocationJob.store(agentsEntity.getAdminName(), agentsEntity.getAdminId().toString(), receiverEntityList, agentsEntity.getMerchantCode(), agentsEntity.getStageCode(), createBy);
    }

    /**
     * 语言转单
     *
     * @param collectionNo
     * @param language
     */
    public void updateLanguage(String collectionNo, String language) {
        LOGGER.info("== 开始更改语言 ==,collectionNo:{},language:{}", collectionNo, language);

        //查询是否存在
        ClReceiverEntity receiverEntity = receiverDao.selectByCollectionNo(collectionNo);
        if (receiverEntity == null) {
            LOGGER.error("== 当前订单不存在 ==，collectionNo:{}", collectionNo);
            return;
        }

        if (receiverEntity.getUserLanguage().equals(language)) {
            LOGGER.info("== 账单语言一直不需要更改 ==，collectionNo:{}", collectionNo);
            return;
        }

        if (receiverEntity.getStatus().equals(ReceiverStatusEnum.COLLECTION_END.getStatus())) {
            LOGGER.info("== 账单已经结束催收 ==，collectionNo:{}", collectionNo);
            return;
        }

        //变更催收具体的状态，修改账单的语言信息 、状态
        ClAllocationDetailEntity currentAllocationByCollectionNo = allocationDetailDao.getCurrentAllocationByCollectionNo(receiverEntity.getCollectionNo());
        if (currentAllocationByCollectionNo == null) {
            LOGGER.info("== 找不到对应的batch detail ==，collectionNo:{}", collectionNo);
        }

        currentAllocationByCollectionNo.setStatus(AllocationStatusEnum.TRANSFERRED.getStatus());
        allocationDetailDao.updateByPrimaryKey(currentAllocationByCollectionNo);

        receiverEntity.setUserLanguage(language);
        receiverEntity.setStatus(ReceiverStatusEnum.INIT.getStatus());
        receiverDao.updateByPrimaryKey(receiverEntity);

        LOGGER.info("== 更改语言成功 ==,collectionNo:{},language:{}", collectionNo, language);
    }

    /**
     * 查询当前催收的分单
     *
     * @param conditions
     * @param page
     * @return
     */
    public List<ClAllocationInfoEntity> getCollectionAgentAllocationList(ClSearchConditions conditions, Page page, boolean cache) {
        if (StringUtils.isEmpty(conditions.getMerchantCode())) {
            throw new ApplicationException("商户号不能为空");
        }
        String conditionsStr = JSON.toJSONString(conditions);
        LOGGER.info("== getCollectionAgentAllocationList  ==,params:{}", conditionsStr);
        Map<String, Object> params = JSON.parseObject(conditionsStr, HashMap.class);
        if (conditions.getSort() != null && StringUtils.isNotEmpty(conditions.getSortType())) {
            if ("last_handle_time".equals(conditions.getSortType()) || "lastCall".equals(conditions.getSortType())) {
                params.put("orderBy", "cad.last_handle_time " + (conditions.getSort() == 1 ? "ASC" : "DESC") + ", cr.id");
            }
            if ("repaymentDate".equals(conditions.getSortType())) {
                params.put("orderBy", "crd.repayment_date " + (conditions.getSort() == 1 ? "ASC" : "DESC") + ", cr.id");
            }
            if ("nextTime".equals(conditions.getSortType())) {
                params.put("orderBy", "cad.next_time " + (conditions.getSort() == 1 ? "ASC" : "DESC") + ", cr.id");
            }
        } else {
            params.put("orderBy", "cr.id");
        }

        LOGGER.info("== 查询分单列表  参数==,params:{}", JsonStream.serialize(params));
        String admin = conditions.getAdminId() + "";
        if (StringUtils.isEmpty(admin)) {
            admin = "NULL";
        }
        Integer totalCount = null;
        List<ClAllocationInfoEntity> clAllocationInfoEntityList = null;
        if (cache) {
            String paramsMd5 = MD5.md5(conditionsStr);
            totalCount = redisClient.get(RedisKey.COLLECTION_TOTAL_COUNT_KEY, admin, paramsMd5);
            clAllocationInfoEntityList = allocationDetailDao.selectAllocationFullInfoList(params, page, totalCount);
            if (totalCount == null && page.getTotalCount() != null) {
                redisClient.set(RedisKey.COLLECTION_TOTAL_COUNT_KEY, page.getTotalCount(), 300, admin, paramsMd5);
                LOGGER.info("设置催收订单总数缓存,totalCount:{},paramsMd5:{},conditionsStr:{}", page.getTotalCount(), paramsMd5, conditionsStr);
            }
        } else {
            clAllocationInfoEntityList = allocationDetailDao.selectAllocationFullInfoList(params, page, null);
        }
        return clAllocationInfoEntityList;
    }

    /**
     * 逾期分单列表
     *
     * @param clOrderSearchConditions
     * @param page
     * @return
     */
    public List<ClOrderAllocationEntity> getCollectionOrderList(ClOrderSearchConditions clOrderSearchConditions, Page page) {
        if (StringUtils.isEmpty(clOrderSearchConditions.getMerchantCode())) {
            throw new ApplicationException("商户号不能为空");
        }
        Map<String, Object> params = JSON.parseObject(JSON.toJSONString(clOrderSearchConditions), HashMap.class);
        List<ClOrderAllocationEntity> clOrderAllocationEntityList = allocationDetailDao.selectOrderAllocationList(params, page);
        return clOrderAllocationEntityList;
    }

    /**
     * 查询当前催收的分单
     *
     * @param adminId
     * @param conditions
     * @param page
     * @return
     */
    public List<CollectionDataDto> getCollectionAgentV2(Integer adminId, ClSearchConditions conditions, Page page) {
        //查询到当前催收的有效批次
        List<ClAllocationBatchEntity> activeListByAdminId = allocationBatchDao.getActiveListByAdminId(adminId);
        if (CollectionUtils.isEmpty(activeListByAdminId)) {
            LOGGER.info("== 没有查询到有效的批次 ==，activeListByAdminId:{}", activeListByAdminId);
            return new ArrayList<>();
        }

        //查询到批次的详情信息
        List<String> batchNoList = activeListByAdminId.parallelStream().map(ClAllocationBatchEntity::getBatchNo).collect(Collectors.toList());
        List<ClAllocationDetailEntity> listByBatchNosAndPage = allocationDetailDao.getListByBatchNosAndPage(batchNoList, page.getStartIndex(), page.getPageSize());

        List<String> allocationNos = listByBatchNosAndPage.parallelStream().map(ClAllocationDetailEntity::getAllocationNo).collect(Collectors.toList());


        List<String> collectionNos = listByBatchNosAndPage.parallelStream().map(ClAllocationDetailEntity::getCollectionNo).collect(Collectors.toList());
        List<ClReceiverEntity> receiverEntityList = receiverDao.selectByCollectionNos(collectionNos);
        Map<String, ClReceiverEntity> collectionNoAndReceiverMap = new HashMap<>();
        receiverEntityList.forEach(r -> {
            collectionNoAndReceiverMap.put(r.getCollectionNo(), r);
        });

        List<ClReceiverDetailEntity> clReceiverDetailEntities = receiverDetailDao.selectListByCollectionNos(collectionNos);
        Map<String, ClReceiverDetailEntity> collectionNoAndDetailMap = new HashMap<>();
        clReceiverDetailEntities.forEach(dt -> {
            collectionNoAndDetailMap.put(dt.getCollectionNo(), dt);
        });

        Map<String, ClCommentEntity> collectionNoAndCommentMap = new HashMap<>();
        List<ClCommentEntity> latestListByAllocationNos = clCommentDao.getLatestListByAllocationNos(allocationNos);
        latestListByAllocationNos.forEach(c -> {
            collectionNoAndCommentMap.put(c.getCollectionNo(), c);
        });

        List<CollectionDataDto> collectionDataDtos = new ArrayList<>();
        listByBatchNosAndPage.forEach(al -> {

            String collectionNo = al.getCollectionNo();
            CollectionDataDto collectionDataDto = new CollectionDataDto()
                    .setCollectionNo(collectionNo)
                    .setAllocationDetailEntity(al)
                    .setReceiverDetailEntity(collectionNoAndDetailMap.get(collectionNo))
                    .setReceiverEntity(collectionNoAndReceiverMap.get(collectionNo))
                    .setCommentEntity(collectionNoAndCommentMap.get(collectionNo));

            collectionDataDtos.add(collectionDataDto);
        });

        page.setTotalCount(allocationDetailDao.countByBatchNosAndPage(batchNoList));

        return collectionDataDtos;
    }

    /**
     * 将用户撞库设置为活跃
     *
     * @param jsonObject
     * @return
     */
    @Transactional
    public boolean updateActiveReceiver(JSONObject jsonObject) {
        try {
            ClReceiverEntity entity = receiverDao.selectLastByBillNoAndNotPay(jsonObject.getString("billNo"));
            if (entity == null) {
                return false;
            }
            ClReceiverDetailEntity detailEntity = receiverDetailDao.selectOneByCollectionNo(entity.getCollectionNo());
            if (detailEntity == null) {
                return false;
            }
            Integer count = clCommentDao.selectTodayCommonByCollectionNo(entity.getCollectionNo(), CollectionStatusEnums.ACTIVE.getType());
            if (count > 0) {
                return false;
            } else {
                activeTag(detailEntity, entity, "0", jsonObject.getString("app"), "A");
                return true;
            }
        } catch (Exception e) {
            LOGGER.error("更新活跃失败", e);
            return false;
        }
    }

    /**
     * 登陆用户活跃
     *
     * @param
     * @return
     */
    @Transactional
    public boolean updateActiveReceiverByLogin(String mobile, String packageName, String source) {
        List<ClReceiverDetailEntity> collections = receiverDetailDao.getClReceiverDetailEntityByMobile(mobile);
        if (CollectionUtils.isEmpty(collections)) {
            LOGGER.info("催收单号为空。。。。");
            return false;
        }
        for (ClReceiverDetailEntity c : collections) {
            ClReceiverEntity entity = receiverDao.selectByCollectionNo(c.getCollectionNo());
            if (entity == null) {
                continue;
            }
            Integer count = clCommentDao.selectTodayCommonByCollectionNo(entity.getCollectionNo(), CollectionStatusEnums.ACTIVE.getType());
            if (count <= 0) {
                activeTag(c, entity, source, "A", packageName);
            }
        }
        return true;
    }

    private void activeTag(ClReceiverDetailEntity c, ClReceiverEntity entity, String type, String thirdAppCode, String packageName) {
        ClCommentEntity clCommentEntity = new ClCommentEntity();
        clCommentEntity.setAllocationNo("")
                .setCollectionNo(entity.getCollectionNo())
                .setCallingResult("")
                .setContent("Recently Active User")
                .setMobile(c.getMobile())
                .setName(c.getName())
                .setRelation("")
                .setFollowId(0)
                .setFollowUp("System")
                .setDeviceType(type + "-" + thirdAppCode + "-" + packageName)
                .setType(CollectionStatusEnums.ACTIVE.getType());
        clCommentDao.insert(clCommentEntity);
        //更新活跃时间
        entity.setLastActiveDate(new Date());
        receiverDao.updateByPrimaryKey(entity);
    }


    /**
     * 活跃失效
     *
     * @param collectionNo
     * @return
     */
    public boolean invalidateActive(String collectionNo) {
        try {
            ClReceiverEntity entity = receiverDao.selectUnsettledByCollectionNo(collectionNo);
            if (entity == null) {
                return true;
            }
            entity.setLastActiveDate(DateUtil.getDate("1970-01-01", "yyyy-MM-dd"));
            //更新活跃时间
            receiverDao.updateByPrimaryKey(entity);
            return true;
        } catch (Exception e) {
            LOGGER.error("活跃失效异常,{}", collectionNo, e);
            return false;
        }
    }

    public List<UniqueStatsVo> getUniqueStats(String stageCode, Date startDate, Date endDate, String merchantCode) {
        List<UniqueStatsVo> agentUniqueStats = allocationDetailDao.getAgentUniqueStats(stageCode, startDate, endDate, merchantCode);
        List<Integer> adminIds = agentUniqueStats.parallelStream().map(UniqueStatsVo::getAdminId).collect(Collectors.toList());
        List<Long> adminIdsLong = new ArrayList<>();
        adminIds.forEach(id -> {
            long l = id.longValue();
            adminIdsLong.add(l);
        });

        List<Admin> adminListByIdList = adminService.getAdminListByIdList(adminIdsLong);
        Map<Long, Admin> adminMap = new HashMap<>();
        adminListByIdList.forEach(admin -> {
            adminMap.put(admin.getId(), admin);
        });

        if (CollectionUtils.isNotEmpty(agentUniqueStats)) {
            agentUniqueStats.forEach(s -> {
                s.setPaidRateStr(new BigDecimal(s.getPaidNum() * 100.0 / s.getTotalNum()).setScale(3, BigDecimal.ROUND_UP) + "%");
                long l = s.getAdminId().longValue();
                Admin admin = adminMap.get(l);
                s.setAdminName(admin == null ? "--" : admin.getName());
            });
        }

        return agentUniqueStats;
    }

    public List<UniqueStatsVo> getAllStats(Date startDate, Date endDate, Integer adminId, String merchantCode) {
        List<UniqueStatsVo> agentUniqueStats = allocationDetailDao.getAgentAllStats(startDate, endDate, adminId, merchantCode);
        Admin oneAdminByAdmin = adminService.getOneAdminByAdmin(Long.valueOf(adminId));
        if (CollectionUtils.isNotEmpty(agentUniqueStats)) {
            agentUniqueStats.forEach(s -> {
                s.setPaidRateStr(new BigDecimal(s.getPaidNum() * 100.0 / s.getTotalNum()).setScale(3, BigDecimal.ROUND_UP) + "%");
                s.setAdminName(oneAdminByAdmin.getName());
            });
        }

        return agentUniqueStats;
    }

    public List<UniqueStatsVo> getAllStatsGroup(String stageCode, Date startDate, Date endDate, String merchantCode) {
        List<UniqueStatsVo> agentUniqueStats = allocationDetailDao.getAgentAllStatsGroup(stageCode, startDate, endDate, merchantCode);
        List<Integer> adminIds = agentUniqueStats.parallelStream().map(UniqueStatsVo::getAdminId).collect(Collectors.toList());
        List<Long> adminIdsLong = new ArrayList<>();
        adminIds.forEach(id -> {
            long l = id.longValue();
            adminIdsLong.add(l);
        });

        List<Admin> adminListByIdList = adminService.getAdminListByIdList(adminIdsLong);
        Map<Long, Admin> adminMap = new HashMap<>();
        adminListByIdList.forEach(admin -> {
            adminMap.put(admin.getId(), admin);
        });

        if (CollectionUtils.isNotEmpty(agentUniqueStats)) {
            agentUniqueStats.forEach(s -> {
                s.setPaidRateStr(new BigDecimal(s.getPaidNum() * 100.0 / s.getTotalNum()).setScale(3, BigDecimal.ROUND_UP) + "%");
                long l = s.getAdminId().longValue();
                Admin admin = adminMap.get(l);
                s.setAdminName(admin == null ? "--" : admin.getName());
            });
        }

        return agentUniqueStats;
    }

    /**
     * 数据校验
     *
     * @param clOrderReceiveRequest
     * @param merchant
     * @return
     */
    private String dataCheck(ClOrderReceiveRequest clOrderReceiveRequest, ClMerchantEntity merchant) {
        if (StringUtils.isEmpty(clOrderReceiveRequest.getToken())) {
            return "token cannot be empty";
        }
        if (StringUtils.isEmpty(clOrderReceiveRequest.getTradeNo())) {
            return "orderNo cannot be empty";
        }
        if (StringUtils.isEmpty(clOrderReceiveRequest.getUserCode())) {
            return "userCode cannot be empty";
        }
        if (clOrderReceiveRequest.getUserInfo() == null) {
            return "user info cannot be null";
        }
        if (clOrderReceiveRequest.getOrderInfo() == null) {
            return "order info cannot be null";
        }

        ClUserInfoInputVo userInfo = clOrderReceiveRequest.getUserInfo();
        if (StringUtils.isEmpty(userInfo.getMobile())) {
            return "mobile cannot be empty";
        }
        if (StringUtils.isEmpty(userInfo.getEmail())) {
            return "email cannot be empty";
        }
//        if (StringUtils.isEmpty(userInfo.getUserLanguage())) {
//            return "language cannot be empty";
//        }
//        if (StringUtils.isEmpty(userInfo.getState())) {
//            return "state cannot be empty";
//        }
//        if (StringUtils.isEmpty(userInfo.getCity())) {
//            return "city cannot be empty";
//        }
//        if (StringUtils.isEmpty(userInfo.getAddress())) {
//            return "address cannot be empty";
//        }
        if (userInfo.getSex() == null) {
            return "sex cannot be empty";
        }
        if (StringUtils.isEmpty(userInfo.getBirthday())) {
            return "birthday cannot be empty";
        }
        if (StringUtils.isEmpty(userInfo.getPanCardNo())) {
            return "panCardNo cannot be empty";
        }
        if (StringUtils.isEmpty(userInfo.getAadhaarNo())) {
            return "aadhaar cannot be empty";
        }
        if (userInfo.getEducation() == null || ClUserEducationEnum.getEnum(userInfo.getEducation()) == null) {
            return "education cannot be empty";
        }
        if (userInfo.getMarriedStatus() == null || ClUserMarriageEnum.getEnum(userInfo.getMarriedStatus()) == null) {
            return "marital cannot be empty";
        }
        if (StringUtils.isEmpty(userInfo.getContact1Name())) {
            return "contact1Name cannot be empty";
        }
        if (StringUtils.isEmpty(userInfo.getContact1Mobile())) {
            return "contact1Mobile cannot be empty";
        }
        if (userInfo.getContact1Relative() == null || ClUserContactTypeEnum.getEnum(userInfo.getContact1Relative()) == null) {
            return "contact1Relative cannot be empty";
        }
        if (StringUtils.isEmpty(userInfo.getContact2Name())) {
            return "contact2Name cannot be empty";
        }
        if (StringUtils.isEmpty(userInfo.getContact2Mobile())) {
            return "contact2Mobile cannot be empty";
        }
        if (userInfo.getContact2Relative() == null || ClUserContactTypeEnum.getEnum(userInfo.getContact2Relative()) == null) {
            return "contact2Relative cannot be empty";
        }
        if (StringUtils.isEmpty(userInfo.getPinCode())) {
            return "pincode cannot be empty";
        }

        ClOrderInputVo orderInfo = clOrderReceiveRequest.getOrderInfo();
        if (StringUtils.isEmpty(orderInfo.getBorrowCapital())) {
            return "borrowCapital cannot be empty";
        }

        if (StringUtils.isEmpty(orderInfo.getReceivedCapital())) {
            return "receivedCapital cannot be empty";
        }
        if (StringUtils.isEmpty(orderInfo.getInterest())) {
            return "interest cannot be empty";
        }
        if (StringUtils.isEmpty(orderInfo.getLateFeeRatio())) {
            return "lateFeeRatio cannot be empty";
        }
        if (StringUtils.isEmpty(orderInfo.getChannel())) {
            return "channel cannot be empty";
        }
        if (StringUtils.isEmpty(orderInfo.getReceivedDate())) {
            return "receivedDate cannot be empty";
        }
        if (StringUtils.isEmpty(orderInfo.getRepaymentDate())) {
            return "repaymentDate cannot be empty";
        }
        if (orderInfo.getBorrowType() == null) {
            return "borrowType cannot be empty";
        }

        return "";
    }

    /**
     * 数据补全
     *
     * @param request
     * @param merchant
     */
    private void dataCompletion(ClOrderReceiveRequest request, ClMerchantEntity merchant) {
        String appName = StringUtils.isNotEmpty(request.getAppName()) ? request.getAppName() : merchant.getAppName();

        if (StringUtils.isEmpty(request.getOrderBillNo())) {
            request.setOrderBillNo(request.getTradeNo());
        }
        if (StringUtils.isEmpty(request.getProductType())) {
            request.setProductType(appName);
        }
        if (StringUtils.isEmpty(request.getProductCode())) {
            request.setProductCode(appName);
        }
        if (StringUtils.isEmpty(request.getAppName())) {
            request.setAppName(appName);
        }

        if (StringUtils.isEmpty(request.getUserInfo().getKycNo())) {
            if (StringUtils.isNotEmpty(request.getUserInfo().getAadhaarNo())) {
                request.getUserInfo().setKycNo(request.getUserInfo().getAadhaarNo());
            } else if (StringUtils.isNotEmpty(request.getUserInfo().getPanCardNo())) {
                request.getUserInfo().setKycNo(request.getUserInfo().getPanCardNo());
            }
        }
        if (StringUtils.isEmpty(request.getUserInfo().getUserLanguage())) {
            request.getUserInfo().setUserLanguage("Hindi");
        }
        if (StringUtils.isEmpty(request.getUserInfo().getState())) {
            request.getUserInfo().setState("");
        }
        if (StringUtils.isEmpty(request.getUserInfo().getCity())) {
            request.getUserInfo().setCity("");
        }
        if (StringUtils.isEmpty(request.getUserInfo().getCity())) {
            request.getUserInfo().setAddress("");
        }

        if (StringUtils.isEmpty(request.getOrderInfo().getPaidAmount())) {
            request.getOrderInfo().setPaidAmount("0");
        }
        if (StringUtils.isEmpty(request.getOrderInfo().getDeductAmount())) {
            request.getOrderInfo().setDeductAmount("0");
        }
        if (StringUtils.isEmpty(request.getOrderInfo().getServiceFee())) {
            request.getOrderInfo().setServiceFee("0");
        }
        if (StringUtils.isEmpty(request.getOrderInfo().getLateServiceFee())) {
            request.getOrderInfo().setLateServiceFee("0");
        }
        if (StringUtils.isEmpty(request.getOrderInfo().getLateFeeRatio())) {
            request.getOrderInfo().setLateFeeRatio("0");
        }
        if (request.getOrderInfo().getBorrowType() == null) {
            request.getOrderInfo().setBorrowType(1);
        }
        if (StringUtils.isEmpty(request.getOrderInfo().getCapitalCode())) {
            request.getOrderInfo().setCapitalCode("-1");
        }
    }

    /**
     * 数据校验
     *
     * @param request
     * @return
     */
    private String dataCheck(ClRepaymentRequest request) {
        if (StringUtils.isEmpty(request.getTradeNo())) {
            return "tradeNo cannot be empty";
        }
        if (StringUtils.isEmpty(request.getRepayBizNo())) {
            return "repayBizNo cannot be empty";
        }
        if (StringUtils.isEmpty(request.getTotalPaidAmount())) {
            return "totalPaidAmount cannot be empty";
        }
        if (StringUtils.isEmpty(request.getTotalDeductAmount())) {
            return "totalDeductAmount cannot be empty";
        }
        if (StringUtils.isEmpty(request.getPaidAmount())) {
            return "paidAmount cannot be empty";
        }
        if (StringUtils.isEmpty(request.getDeductAmount())) {
            return "deductAmount cannot be empty";
        }
        if (StringUtils.isEmpty(request.getRepayDate())) {
            return "repayDate cannot be empty";
        }
        if (request.getPaidStatus() == null) {
            return "paidStatus cannot be empty";
        }
        return "";
    }

    public static void main(String[] args) {
        DateUtil.getDate("", "yyyy-MM-dd HH:mm:ss");
    }
}
